「このデバイス(IMEI)で使っているSIM(IMSI)はどれ?」を調べてみた(AWS Lambdaで)
できるけど、これで十分なのかは要件次第ですね。
SORACOMには、開発者向けにAPIが提供されています。
今回は、「このデバイス(IMEI)って、どのSIM(IMSI)を使ってるんだっけ?」をあとで調べる方法があるか、SORACOM APIを使って試してみました。
おすすめの方
- SORACOM APIを使いたい方
- SORACOM APIをLambdaで使いたい方
- SORACOM APIでIMEIからSIM(IMSI)を調べたい方
- AWS SAMでLambdaを作りたい方
- パラメータストアのSecureStringをLambdaで取得したい方
SORACOM APIを使う準備
- SAMユーザ作成
- 認証情報取得
- SAMユーザのアクセス権限付与
- System ManagerのパラメータストアにSORACOM SAMユーザの認証情報を格納
- 認証キーID
- 認証キーシークレット
上記については、次のブログを参考に行います。
なお、今回のアクセス権限は下記となります。
{ "statements": [ { "api": [ "Subscriber:listSubscribers" ], "effect": "allow" } ] }
Lambdaを作る
sam init
sam init \ --runtime python3.8 \ --name Lambda-Soracom-Api-Search-Imsi-Sample \ --app-template hello-world \ --package-type Zip
SAMテンプレート
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Lambda-Soracom-Api-Search-Imsi-Sample Parameters: SoracomKeyId: Type: AWS::SSM::Parameter::Value<String> Default: /SORACOM/SAM/KeyId Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.8 Timeout: 10 Policies: - arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess Environment: Variables: SORACOM_KEY_ID: !Ref SoracomKeyId Events: HelloWorld: Type: Api Properties: Path: /hello Method: get HelloWorldFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction} Outputs: HelloWorldApi: Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
requirements.txt
requests
Lambdaコード
お試し実装のため、下記となっています。本番運用時には適宜検討し、実装してください。
- APIトークンの有効期限はデフォルト設定です。
- レートリミットの考慮をしていません。
SORACOM API リファレンスを見る限り、「IMEIを指定して、情報取得する」というAPIは無さそうです。 そのため、下記の手順で探しました。
- 所持しているSIM情報の一覧を取得する
- 「最新のセッション情報内のIMEI」と「探したいIMEI」が一致するSIM情報を探す
なお、IMEIはセッション情報内に存在するため、次の点に注意する必要があります。今回は未考慮です。
- 該当のSIMが1度もデータ送信してない可能性
- 該当のSIMと機材(IMEI)の組み合わせが古い可能性
- 該当のSIMと機材(IMEI)の組み合わせが複数ある可能性
また、SIMがたくさんある場合は、SIM情報取得時に条件マッチを活用すると良いですね。
- tag_name
- tag_value
- status_filter
- など
import os import json import boto3 import requests from typing import Tuple, Optional ssm = boto3.client('ssm') SORACOM_ENDPOINT = 'https://api.soracom.io/v1' IMEI = '3xxxxxxxxxxxxx0' def lambda_handler(event, context): soracom_key_id = os.environ['SORACOM_KEY_ID'] soracom_secret = get_soracom_secret() api_key, token = get_token(soracom_key_id, soracom_secret) subscribers = get_subscribers(api_key, token) imsi = search_imsi_by_imei(subscribers, IMEI) return { 'statusCode': 200, 'body': json.dumps({ 'imei': IMEI, 'imsi': imsi, }), } def get_soracom_secret() -> str: res = ssm.get_parameter( Name='/SORACOM/SAM/Secret', WithDecryption=True ) return res['Parameter']['Value'] def get_token(soracom_key_id, soracom_secret) -> Tuple[str, str]: headers = {'Content-Type': 'application/json'} data = { 'authKeyId': soracom_key_id, 'authKey': soracom_secret, } resp = requests.post(f'{SORACOM_ENDPOINT}/auth', headers=headers, data=json.dumps(data)) d = resp.json() return d['apiKey'], d['token'] def get_subscribers(api_key: str, token: str) -> list: headers = { 'Content-Type': 'application/json', 'X-Soracom-API-Key': api_key, 'X-Soracom-Token': token, } resp = requests.get(f'{SORACOM_ENDPOINT}/subscribers', headers=headers) return resp.json() def search_imsi_by_imei(subscribers: list, imei: str) -> Optional[str]: for item in subscribers: if 'sessionStatus' not in item: continue if item['sessionStatus']['imei'] == imei: return item['imsi'] return None
デプロイ
sam build sam package \ --output-template-file packaged.yaml \ --s3-bucket cm-fujii.genki-deploy sam deploy \ --template-file packaged.yaml \ --stack-name Lambda-Soracom-Api-Search-Imsi-Sample-Stack \ --s3-bucket cm-fujii.genki-deploy \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
APIエンドポイントを確認する
aws cloudformation describe-stacks \ --stack-name Lambda-Soracom-Api-Search-Imsi-Sample-Stack \ --query 'Stacks[].Outputs'
動作確認
API Gatewayのエンドポイントにアクセスすると、IMSIが返ってきました。
$ curl https://xxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello {"imei": "3xxxxxxxxxxxxx0", "imsi": "4xxxxxxxxxxxxx8"}